#include <map>

#include "tests.h"

TEST(map, ConstructorDefault) {
  s21::map<char, long int> s21_empty_map;
  std::map<char, long int> orig_empty_map;
  EXPECT_EQ(s21_empty_map.empty(), orig_empty_map.empty());
}

TEST(map, Constructor1) {
  s21::map<char, char> s21_map = {};
  std::map<char, char> orig_map = {};
  EXPECT_EQ(s21_map.size(), orig_map.size());
  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  EXPECT_TRUE(s21_it->first == orig_it->first);
  EXPECT_TRUE(s21_it->second == orig_it->second);
}

TEST(map, ConstructorInitializer) {
  s21::map<int, char> s21_map = {{1, 'S'}, {2, 'c'}, {3, 'h'},
                                 {4, 'o'}, {5, 'o'}, {6, 'l'},
                                 {7, ' '}, {8, '2'}, {9, '1'}};
  std::map<int, char> orig_map = {{1, 'S'}, {2, 'c'}, {3, 'h'},
                                  {4, 'o'}, {5, 'o'}, {6, 'l'},
                                  {7, ' '}, {8, '2'}, {9, '1'}};
  EXPECT_EQ(s21_map.size(), orig_map.size());
  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
}

TEST(map, ConstructorCopy) {
  s21::map<char, unsigned int> s21_map = {
      {1, 1}, {-12, 144}, {6, 36}, {-20, 400}, {11, 121}};
  std::map<char, unsigned int> orig_map = {
      {1, 1}, {-12, 144}, {6, 36}, {-20, 400}, {11, 121}};
  s21::map<char, unsigned int> s21_map_copy = s21_map;
  std::map<char, unsigned int> orig_map_copy = orig_map;
  EXPECT_EQ(s21_map_copy.size(), orig_map_copy.size());
  auto s21_it = s21_map_copy.begin();
  auto orig_it = orig_map_copy.begin();
  for (; s21_it != s21_map_copy.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
}

TEST(map, ConstructorMoveMap) {
  s21::map<int, double> s21_map = {{1, 1.0},
                                   {5, 2.236067977},
                                   {2, 1.414213562},
                                   {9, 3.0},
                                   {2024, 44.988887517}};
  std::map<int, double> orig_map = {{1, 1.0},
                                    {5, 2.236067977},
                                    {2, 1.414213562},
                                    {9, 3.0},
                                    {2024, 44.988887517}};
  s21::map<int, double> s21_map_copy = std::move(s21_map);
  std::map<int, double> orig_map_copy = std::move(orig_map);
  EXPECT_EQ(s21_map.size(), orig_map.size());
  EXPECT_EQ(s21_map_copy.size(), orig_map_copy.size());

  auto s21_it = s21_map_copy.begin();
  auto orig_it = orig_map_copy.begin();
  for (; s21_it != s21_map_copy.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
}

TEST(map, MoveAssignmentOperator) {
  s21::map<int, double> s21_map = {{1, 1.0},
                                   {5, 2.236067977},
                                   {2, 1.414213562},
                                   {9, 3.0},
                                   {2024, 44.988887517}};
  std::map<int, double> orig_map = {{1, 1.0},
                                    {5, 2.236067977},
                                    {2, 1.414213562},
                                    {9, 3.0},
                                    {2024, 44.988887517}};
  s21::map<int, double> s21_map_copy;
  std::map<int, double> orig_map_copy;
  s21_map_copy = std::move(s21_map);
  orig_map_copy = std::move(orig_map);
  EXPECT_EQ(s21_map.size(), orig_map.size());
  EXPECT_EQ(s21_map_copy.size(), orig_map_copy.size());

  auto s21_it = s21_map_copy.begin();
  auto orig_it = orig_map_copy.begin();
  for (; s21_it != s21_map_copy.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
}

TEST(map, MapOperator) {
  s21::map<unsigned char, std::string> s21_map = {
      {12, "XII"},  {21, "XXI"},     {37, "XXVII"}, {9, "IX"},
      {49, "XLIX"}, {224, "CCXXIV"}, {108, "CVII"}};
  std::map<unsigned char, std::string> orig_map = {
      {12, "XII"},  {21, "XXI"},     {37, "XXVII"}, {9, "IX"},
      {49, "XLIX"}, {224, "CCXXIV"}, {108, "CVII"}};
  orig_map[156] = "CLVI";
  orig_map[12] = "TWELVE";
  EXPECT_TRUE(s21_map[21] == orig_map[21]);
  EXPECT_FALSE(s21_map[12] == orig_map[12]);
}

TEST(map, AtOperatorException) {
  s21::map<char, std::string> s21_map = {
      {'N', "NORD"}, {'S', "SOUTH"}, {'W', "WEST"}};
  EXPECT_THROW(s21_map.at('E') = "EAST", std::out_of_range);
}

TEST(map, AtOperator) {
  s21::map<char, std::string> s21_map = {{'a', "and"},
                                         {'o', "or"},
                                         {'r', "read"},
                                         {'w', "write"},
                                         {'x', "execute"}};
  std::map<char, std::string> orig_map = {{'a', "and"},
                                          {'o', "or"},
                                          {'r', "read"},
                                          {'w', "write"},
                                          {'x', "execute"}};
  s21_map.at('a') = "all";
  orig_map.at('a') = "all";
  orig_map.at('r') = "recursive";
  EXPECT_TRUE(s21_map['a'] == orig_map['a']);
  EXPECT_FALSE(s21_map['r'] == orig_map['r']);
  EXPECT_TRUE(s21_map['x'] == orig_map['x']);
}

TEST(map, Capacity) {
  s21::map<char, std::string> s21_map;
  std::map<char, std::string> orig_map;
  EXPECT_TRUE(s21_map.empty() == orig_map.empty());
  s21_map.insert('1', "one");
  s21_map.insert('2', "two");
  s21_map.insert('3', "three");
  EXPECT_FALSE(s21_map.empty() == orig_map.empty());
  EXPECT_EQ(s21_map.size(), 3);
}

TEST(map, Clear) {
  s21::map<int, int> s21_map;
  std::map<int, int> orig_map;
  s21_map.clear();
  orig_map.clear();
  EXPECT_EQ(s21_map.empty(), orig_map.empty());
  s21_map.insert(std::make_pair(1, 1));
  orig_map.insert(std::make_pair(1, 1));
  EXPECT_EQ(s21_map.empty(), orig_map.empty());
  s21_map.clear();
  orig_map.clear();
  EXPECT_EQ(s21_map.empty(), orig_map.empty());
}

TEST(map, Insert1) {
  s21::map<int, char> s21_map;
  std::map<int, char> orig_map;
  s21_map.insert(std::make_pair(1, 'a'));
  s21_map.insert(std::make_pair(2, 'a'));
  s21_map.insert(std::make_pair(3, 'a'));
  orig_map.insert(std::make_pair(1, 'a'));
  orig_map.insert(std::make_pair(2, 'a'));
  orig_map.insert(std::make_pair(3, 'a'));

  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }

  auto pr1 = s21_map.insert(std::make_pair(1, 'a'));
  auto pr2 = orig_map.insert(std::make_pair(1, 'a'));
  EXPECT_TRUE(pr1.second == pr2.second);
}

TEST(map, Insert2) {
  s21::map<int, char> s21_map;
  std::map<int, char> orig_map;
  s21_map.insert(1, 'a');
  s21_map.insert(2, 'a');
  s21_map.insert(3, 'a');
  orig_map.insert(std::make_pair(1, 'a'));
  orig_map.insert(std::make_pair(2, 'a'));
  orig_map.insert(std::make_pair(3, 'a'));

  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }

  auto pr1 = s21_map.insert(1, 'a');
  auto pr2 = orig_map.insert(std::make_pair(1, 'a'));
  EXPECT_TRUE(pr1.second == pr2.second);
}

TEST(map, Insert3) {
  s21::map<int, char> s21_map = {{1, 'a'}};
  std::map<int, char> orig_map = {{1, 'a'}};
  s21_map.insert(2, 'a');
  s21_map.insert(3, 'a');
  orig_map.insert(std::make_pair(2, 'a'));
  orig_map.insert(std::make_pair(3, 'a'));

  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
  auto pr1 = s21_map.insert_or_assign(1, 'b');
  auto i = orig_map.begin();
  EXPECT_TRUE(pr1.first->first == i->first);
  EXPECT_FALSE(pr1.first->second == i->second);
}

TEST(map, Erase1) {
  s21::map<int, char> s21_map = {{1, 'x'}, {2, 'b'}, {3, 'z'}, {4, 'y'}};
  std::map<int, char> orig_map = {{1, 'x'}, {2, 'b'}, {3, 'z'}, {4, 'y'}};
  EXPECT_EQ(s21_map.size(), orig_map.size());
  s21_map.erase(s21_map.begin());
  orig_map.erase(orig_map.begin());
  EXPECT_EQ(s21_map.size(), orig_map.size());
  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
}

TEST(map, Swap) {
  s21::map<int, int> s21_map = {{1, 1}};
  s21::map<int, int> s21_swap_map = {{3, 3}, {4, 4}};

  s21_map.swap(s21_swap_map);
  EXPECT_EQ(s21_map.size(), 2);
  EXPECT_EQ(s21_swap_map.size(), 1);
  auto x = s21_map.begin()->first;
  auto y = s21_swap_map.begin()->first;
  EXPECT_EQ(x, 3);
  EXPECT_EQ(y, 1);
}

TEST(map, MaxSize) {
  s21::map<int, std::string> map;
  std::map<int, std::string> map1;
  EXPECT_GE(map.max_size(), map1.max_size());
}

TEST(map, Merge) {
  s21::map<int, int> s21_map = {{1, 1}, {4, 4}, {2, 2}};
  s21::map<int, int> s21_map_merge = {{3, 3}, {4, 4}};

  std::map<int, int> orig_map = {{1, 1}, {4, 4}, {2, 2}};
  std::map<int, int> orig_map_merge = {{3, 3}, {4, 4}};

  s21_map.merge(s21_map_merge);
  orig_map.merge(orig_map_merge);

  auto s21_it = s21_map.begin();
  auto orig_it = orig_map.begin();
  for (; s21_it != s21_map.end(); ++s21_it, ++orig_it) {
    EXPECT_TRUE(s21_it->first == orig_it->first);
    EXPECT_TRUE(s21_it->second == orig_it->second);
  }
  EXPECT_EQ(s21_map_merge.contains(4),
            orig_map_merge.find(4) != orig_map.end());
  EXPECT_EQ(s21_map_merge.contains(3),
            orig_map_merge.find(3) == orig_map.end());
}

TEST(map, InsertMany) {
  std::map<int, int> orig_map = {{1, 1}, {2, 2}};
  s21::map<int, int> s21_map = {{1, 1}, {2, 2}};
  orig_map.insert({3, 3});
  orig_map.insert({4, 4});
  std::pair<int, int> a = {3, 3};
  std::pair<int, int> b = {4, 4};
  s21_map.insert_many(a, b);
  auto it = s21_map.begin();
  auto it1 = orig_map.begin();
  for (; it != s21_map.end(); ++it, ++it1) {
    EXPECT_EQ(it->first, it1->first);
    EXPECT_EQ(it->second, it1->second);
  }
}